#include <bits/stdc++.h>
using namespace std;
using ll = long long;

const ll mod = 1e9 + 7;
const int N = 2 * 1e6 + 7;
int l[N], r[N]; // 记录前缀和
int ans, base, tmp;
/**
 *
 * 每个矿洞坐标的矿数量记为对应价值
 * 原点价值无论如何都可以拿到 这里我们记录数值 最后加上
 *
 * 用两个数组l r 表示距离原点距离i的范围内所有矿洞价值前缀和
 * base记录原点价值
 *
 * 这里设置前缀和仅需要设置可探索范围即[-m,m]范围
 *
 * 分析可知 总步数消耗为一侧的两倍加另一侧的单倍
 * (其中一侧要走来回 即回头路段)
 *
 * 遍历回头路的长度 可得到另一侧的可供探索的剩余步数
 *
 * 求和 原点两侧的总价值 更新最大值 加上原点值即为答案
 */
int main()
{
  ios::sync_with_stdio(0), cin.tie(0);
  int n, m;
  cin >> n >> m;
  // 摆放矿物
  for (int i = 0; i < n; i++)
  {
    cin >> tmp;
    /**
     * 这里可能不按顺序,有的数据无法更新
     * 后面单独设置前缀和
     */
    if (tmp > 0)
      r[tmp] += 1;
    else if (tmp < 0)
      l[abs(tmp)] += 1;
    else
      base += 1; // 原点特判
  }
  // 这里设置前缀和仅需要设置可探索范围即[-m,m]范围
  for (int i = 1; i <= m; i++)
  {
    l[i] += l[i - 1];
    r[i] += r[i - 1];
  }
  // 初始化为不走回头路的两种极端的最大值
  ans = max({l[m], r[m]});
  // 遍历各种回头路长度的情况
  for (int i = 1; i <= m; i++)
  {
    // 记录可供另一端探索的剩余步数
    tmp = m - 2 * i; // 回头路所以2*
    // 还有步数探索
    if (tmp > 0)
      // 更新对称的两种走法的最大收益
      ans = max({ans, l[i] + r[tmp], r[i] + l[tmp]});
  }
  cout << ans + base; // 加上原点价值
  return 0;
}
